Micron Document
πŸŽ–οΈGitΠ―Ρ€Π°πŸŽ–οΈ


Displaying Rendered β€’ View raw β€’ Download

specs/006-kmp-project-structure/tasks.md bd2863243bab6eb213401d949839a2bc74dde7e2 (bd286324) Text, 19.04 KB

Tasks: KMP Recommended Project Structure Alignment

Input: Design documents from T383838/specs/006-kmp-project-structure/
Prerequisites: plan.md (required), spec.md (required for user stories), research.md, data-model.md, quickstart.md

Tests: No new automated tests are required by this specification. Validation is via existing build and test commands.

Verification: Every phase includes constitution-required validation tasks for formatting, static analysis, and the relevant compile/test commands.

Organization: Tasks are grouped by user story to enable independent implementation and testing. US4 (Legacy DSL Block Migration) is the primary implementation work, subdivided by migration tier.

Format: T383838[ID] [P?] [Story] Description

β€’ [P]: Can run in parallel (different files, no dependencies)
β€’ [Story]: Which user story this task belongs to (e.g., US1, US2, US3, US4)
β€’ Include exact file paths in descriptions

Phase 1: Setup (Baseline & Prerequisites)

Purpose: Establish a clean build baseline and verify the starting state before any changes

β€’ [ ] T001 Verify clean build baseline by running T383838./gradlew assembleDebug :desktop:packageUberJarForCurrentOS allTests and record clean T383838assembleDebug wall-clock time (3 consecutive runs after T383838./gradlew clean, median value) to T383838specs/006-kmp-project-structure/baseline-timing.txt for NFR-001 comparison
β€’ [ ] T002 Verify T383838DESKTOP_ONLY=true ./gradlew :desktop:packageUberJarForCurrentOS passes before migration
β€’ [x] T003 Run T383838grep -rn "android {" core/*/build.gradle.kts feature/*/build.gradle.kts to document all 27 legacy T383838android {} blocks as the pre-migration inventory


Phase 2: Convention Plugin Hardening (US2 β€” Blocking Prerequisite)

Purpose: Harden convention plugin defaults so modules can rely on convention for T383838androidResources.enable = false. This MUST complete before any module migration.

Goal: Convention plugins reflect recommended patterns β€” T383838configureKotlinMultiplatform() absorbs the T383838androidResources.enable = false default so 23 of 27 modules no longer need to set it explicitly.

⚠️ CRITICAL: No module migration (Phase 3–5) can begin until this phase is complete.

Independent Test: T383838./gradlew assembleDebug passes β€” adding the default is backward-compatible since all modules currently override it.

β€’ [x] T004 [US2] Add T383838androidResources.enable = false default to T383838configureKotlinMultiplatform() inside the T383838pluginManager.withPlugin block in T383838build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt (add after T383838minSdk assignment, before namespace auto-derivation)
β€’ [x] T005 [US2] Verify convention plugin change builds successfully: T383838./gradlew assembleDebug :desktop:packageUberJarForCurrentOS allTests

Checkpoint: Convention plugin hardened β€” module migration can now begin


Phase 3: Tier 1 Module Migration β€” Simple Modules (US4, Priority: P1) 🎯 MVP

Goal: Migrate 6 modules where convention handles everything β€” remove T383838android {} block entirely, remove redundant T383838jvm() declarations, remove explicit T383838namespace (auto-derived), remove T383838androidResources.enable = false (convention default).

Independent Test: T383838./gradlew assembleDebug allTests passes after all 6 modules migrated. Verify with T383838grep -rn "android {" core/di/build.gradle.kts core/nfc/build.gradle.kts core/ui/build.gradle.kts core/navigation/build.gradle.kts feature/settings/build.gradle.kts feature/messaging/build.gradle.kts returning zero matches.

Implementation for Tier 1

β€’ [x] T006 [P] [US4] Migrate T383838core/di/build.gradle.kts β€” remove T383838android {} block (namespace auto-derived, resources disabled by convention), remove redundant T383838jvm() if present
β€’ [x] T007 [P] [US4] Migrate T383838core/nfc/build.gradle.kts β€” remove T383838android {} block (namespace auto-derived, resources disabled by convention)
β€’ [x] T008 [P] [US4] Migrate T383838core/ui/build.gradle.kts β€” remove T383838android {} block (namespace auto-derived, resources disabled by convention), remove redundant T383838jvm() if present
β€’ [x] T009 [P] [US4] Migrate T383838core/navigation/build.gradle.kts β€” remove T383838android {} block (namespace auto-derived)
β€’ [x] T010 [P] [US4] Migrate T383838feature/settings/build.gradle.kts β€” remove T383838android {} block (namespace auto-derived, resources disabled by convention)
β€’ [x] T011 [P] [US4] Migrate T383838feature/messaging/build.gradle.kts β€” remove T383838android {} block (namespace auto-derived, resources disabled by convention)
β€’ [x] T012 [US4] Verify Tier 1 batch: T383838./gradlew assembleDebug allTests β€” commit must be independently buildable (NFR-003)

Checkpoint: Tier 1 complete β€” 6 of 27 modules migrated, build passes


Phase 4: Tier 2 Module Migration β€” Standard Modules with Host Tests (US4, Priority: P1)

Goal: Migrate 18 modules that opt into T383838withHostTest {}. Replace T383838android {} with T383838androidLibrary { withHostTest {} }, remove redundant T383838jvm(), remove explicit T383838namespace (auto-derived except T383838feature:wifi-provision), remove T383838androidResources.enable = false (convention default).

Independent Test: T383838./gradlew assembleDebug :desktop:packageUberJarForCurrentOS allTests passes after all 18 modules migrated.

Tier 2a: Modules with T383838withHostTest { isIncludeAndroidResources = true } (13 modules)

β€’ [x] T013 [P] [US4] Migrate T383838core/ble/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T014 [P] [US4] Migrate T383838core/common/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T015 [P] [US4] Migrate T383838core/data/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T016 [P] [US4] Migrate T383838core/domain/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T017 [P] [US4] Migrate T383838core/model/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove T383838androidResources.enable = false
β€’ [x] T018 [P] [US4] Migrate T383838core/network/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T019 [P] [US4] Migrate T383838core/service/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T020 [P] [US4] Migrate T383838core/takserver/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T021 [P] [US4] Migrate T383838feature/connections/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T022 [P] [US4] Migrate T383838feature/firmware/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T023 [P] [US4] Migrate T383838feature/intro/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T024 [P] [US4] Migrate T383838feature/map/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T025 [P] [US4] Migrate T383838feature/node/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true } }, remove explicit namespace, remove T383838androidResources.enable = false

Tier 2b: Modules with empty T383838withHostTest {} (4 modules)

β€’ [x] T026 [P] [US4] Migrate T383838core/datastore/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest {} }, remove redundant T383838jvm(), remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T027 [P] [US4] Migrate T383838core/prefs/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest {} }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T028 [P] [US4] Migrate T383838core/repository/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest {} }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T029 [P] [US4] Migrate T383838core/testing/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest {} }, remove explicit namespace, remove T383838androidResources.enable = false

Tier 2c: Namespace override required (1 module)

β€’ [x] T030 [P] [US4] Migrate T383838feature/wifi-provision/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { namespace = "org.meshtastic.feature.wifiprovision"; withHostTest {} }, remove redundant T383838jvm(), remove T383838androidResources.enable = false (namespace MUST be explicit β€” auto-derived T383838feature.wifi.provision differs from required T383838feature.wifiprovision)

Tier 2 Verification

β€’ [x] T031 [US4] Verify Tier 2 batch: T383838./gradlew assembleDebug :desktop:packageUberJarForCurrentOS allTests and T383838DESKTOP_ONLY=true ./gradlew :desktop:packageUberJarForCurrentOS β€” commit must be independently buildable (NFR-003)

Checkpoint: Tiers 1 + 2 complete β€” 24 of 27 modules migrated, build passes


Phase 5: Tier 3 Module Migration β€” Special Modules (US4, Priority: P1)

Goal: Migrate 3 modules with custom configuration (minSdk override, device tests, resource prefix).

Independent Test: T383838./gradlew assembleDebug :desktop:packageUberJarForCurrentOS allTests passes. All special configurations preserved.

Implementation for Tier 3

β€’ [x] T032 [P] [US4] Migrate T383838core/proto/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { minSdk = 21 } (ATAK compatibility override), remove T383838androidResources.enable = false
β€’ [x] T033 [P] [US4] Migrate T383838core/database/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { withHostTest { isIncludeAndroidResources = true }; withDeviceTest { instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } }, remove explicit namespace, remove T383838androidResources.enable = false
β€’ [x] T034 [P] [US4] Migrate T383838core/resources/build.gradle.kts β€” replace T383838android {} with T383838androidLibrary { androidResources { enable = true; resourcePrefix = "meshtastic_" }; withHostTest { isIncludeAndroidResources = true } }, remove redundant T383838jvm() (resources MUST override convention default to T383838enable = true)
β€’ [x] T035 [US4] Verify Tier 3 batch: T383838./gradlew assembleDebug :desktop:packageUberJarForCurrentOS allTests β€” commit must be independently buildable (NFR-003)

Checkpoint: All 27 KMP modules migrated β€” zero legacy T383838android {} blocks remain


Phase 6: Full Verification & Build Validation (US1, Priority: P1)

Goal: Developer builds successfully after restructuring β€” full verification across all build modes and configurations.

Independent Test: All 4 acceptance scenarios from US1 pass.

β€’ [ ] T036 [US1] Run full Android build: T383838./gradlew assembleDebug β€” verify zero errors
β€’ [ ] T037 [US1] Run full Desktop build: T383838./gradlew :desktop:packageUberJarForCurrentOS β€” verify zero errors
β€’ [ ] T038 [US1] Run all tests: T383838./gradlew allTests β€” verify zero regressions
β€’ [ ] T039 [US1] Run DESKTOP_ONLY mode: T383838DESKTOP_ONLY=true ./gradlew :desktop:packageUberJarForCurrentOS β€” verify succeeds without Android SDK
β€’ [ ] T040 [US1] Compare clean T383838assembleDebug time against baseline from T001 (3 consecutive runs after T383838./gradlew clean, median value, same machine) β€” verify <5% increase (NFR-001)

Checkpoint: US1 complete β€” all build modes verified


Phase 7: Polish & Cross-Cutting Concerns

Purpose: Final validation, cleanup, and constitution compliance

β€’ [x] T041 [P] Verify no legacy T383838android {} blocks remain: T383838grep -rn "android {" core/*/build.gradle.kts feature/*/build.gradle.kts | grep -v "widget\|api\|barcode\|androidLibrary\|androidResources\|androidMain\|androidHostTest\|androidDeviceTest\|androidRuntimeClasspath" β€” must return zero matches (SC-001)
β€’ [x] T042 [P] Verify no redundant T383838jvm() calls remain in migrated modules: T383838grep -n "jvm()" core/*/build.gradle.kts feature/*/build.gradle.kts | grep -v "widget\|api\|barcode" β€” must return zero matches
β€’ [x] T043 [P] Verify T383838configureKotlinMultiplatform() in T383838build-logic/convention/src/main/kotlin/org/meshtastic/buildlogic/KotlinAndroid.kt uses only T383838KotlinMultiplatformAndroidLibraryTarget API β€” no legacy T383838android {} extension configuration (SC-007)
β€’ [x] T044 [P] [US3] Verify module dependency direction is preserved: no T383838core/ module depends on T383838feature/ modules (FR-006)
β€’ [x] T045 [P] Run constitution-required verification: T383838./gradlew spotlessApply spotlessCheck detekt
β€’ [x] T046 [P] Verify Gradle configuration cache, isolated projects, and parallel execution remain functional (NFR-002): T383838./gradlew assembleDebug --configuration-cache
β€’ [ ] T047 Validate quickstart.md in T383838specs/006-kmp-project-structure/quickstart.md matches final implementation β€” update if migration steps differ from what was executed. Ensure guide is generic enough for other Meshtastic platform repos to reference (NFR-004)
β€’ [x] T048 [US2] Add FR-008 enforcement: add a CI-time grep check in Phase 7 verification or a Gradle T383838afterEvaluate assertion in T383838configureKotlinMultiplatform() that fails the build if any KMP module contains a legacy T383838android {} block inside T383838kotlin {} β€” prevents future regressions (FR-008)
β€’ [ ] T049 [P] Verify SC-006: create a temporary scratch module applying T383838meshtastic.kmp.library, confirm it configures correctly for Android + Desktop with no manual T383838android {} block, then remove it


Dependencies & Execution Order

Phase Dependencies

β€’ Setup (Phase 1): No dependencies β€” can start immediately
β€’ Convention Plugin Hardening (Phase 2): Depends on Phase 1 β€” BLOCKS all module migrations
β€’ Tier 1 Migration (Phase 3): Depends on Phase 2 completion
β€’ Tier 2 Migration (Phase 4): Depends on Phase 2 completion (can run in parallel with Phase 3)
β€’ Tier 3 Migration (Phase 5): Depends on Phase 2 completion (can run in parallel with Phases 3–4)
β€’ Full Verification (Phase 6): Depends on Phases 3, 4, and 5 completion
β€’ Polish (Phase 7): Depends on Phase 6 completion

User Story Dependencies

β€’ US2 (Convention Plugins): Phase 2 β€” Must complete first; blocking prerequisite
β€’ US4 (Legacy DSL Migration): Phases 3, 4, 5 β€” Primary implementation; depends on US2
β€’ US1 (Build Verification): Phase 6 β€” Validation of US4 work; depends on all tiers complete
β€’ US3 (Module Boundary Clarity): Verified in Phase 7 (T044) β€” no implementation needed, existing structure already satisfies

Within Each Tier

β€’ All module migrations within a tier marked [P] can run in parallel (different files, no dependencies)
β€’ Tier verification task must run after all module tasks in that tier complete
β€’ Tiers 1, 2, and 3 can themselves run in parallel after Phase 2 completes

Parallel Opportunities

β€’ Phase 2: Sequential (single file change + verification)
β€’ Phase 3: T006–T011 all parallel (6 different T383838build.gradle.kts files)
β€’ Phase 4: T013–T030 all parallel (18 different T383838build.gradle.kts files)
β€’ Phase 5: T032–T034 all parallel (3 different T383838build.gradle.kts files)
β€’ Phase 7: T041–T046 all parallel (independent verification commands)
β€’ Cross-tier: Phases 3, 4, 5 can all run in parallel after Phase 2


Parallel Example: Tier 1 Migration

T282828
T006: core/di/build.gradle.kts
T007: core/nfc/build.gradle.kts
T008: core/ui/build.gradle.kts
T009: core/navigation/build.gradle.kts
T010: feature/settings/build.gradle.kts
T011: feature/messaging/build.gradle.kts

T012: ./gradlew assembleDebug allTests

Parallel Example: Full Tier Parallelism

T282828
Tier 1 (T006–T012): 6 simple modules β€” remove android {} entirely
Tier 2 (T013–T031): 18 standard modules β€” replace with androidLibrary { withHostTest {} }
Tier 3 (T032–T035): 3 special modules β€” custom config (minSdk, device tests, resources)



Implementation Strategy

MVP First (Tier 1 Only)

1. Complete Phase 1: Setup (baseline)
2. Complete Phase 2: Convention plugin hardening (T004–T005)
3. Complete Phase 3: Tier 1 β€” 6 simple modules (T006–T012)
4. STOP and VALIDATE: Build passes, 6 modules proven
5. This alone demonstrates the migration pattern works

Incremental Delivery

1. Setup + Convention Plugin Hardening β†’ Foundation ready
2. Tier 1 (6 modules) β†’ Build verified β†’ Pattern proven (MVP!)
3. Tier 2 (18 modules) β†’ Build verified β†’ Bulk migration complete
4. Tier 3 (3 modules) β†’ Build verified β†’ All 27 modules done
5. Full verification + polish β†’ Ready for PR

Key Risk Mitigation

β€’ Each tier is independently verifiable β€” if Tier 2 breaks, Tier 1 is still valid
β€’ Convention plugin change (T004) is backward-compatible β€” existing explicit overrides in modules are no-ops
β€’ Individual module migrations can be reverted independently (T383838git checkout -- <module>/build.gradle.kts)
β€’ T383838feature:wifi-provision is the only namespace edge case β€” flagged explicitly in T030


Notes

β€’ [P] tasks = different files, no dependencies on each other
β€’ [US4] is the primary user story β€” all module migration tasks belong to it
β€’ No source code files are modified β€” only T383838build.gradle.kts files and one convention plugin T383838.kt file
β€’ The spec lists 28 modules but T383838core:model was counted in both research.md Tier 1 and data-model.md Tier 2 β€” data-model.md (Tier 2 with T383838withHostTest) is authoritative, yielding 27 total KMP modules
β€’ T383838feature:widget, T383838core:api, T383838core:barcode are Android-only and NOT affected by this migration
β€’ Commit after each tier verification for clean rollback points

Served by rngit 1.5.0 - Generated in 0.04s